//
// WinPcap.net
//
// Copyright (C) 2005-2009 Matthew Ward
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Matthew Ward (mrward@users.sourceforge.net)

using System;
using System.Net;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;

namespace WinPcap
{
	/// <summary>
	/// Native WinPcap methods and other helper methods.
	/// </summary>
	/// <remarks>
	/// The helper methods provide a higher level of abstraction and can be
	/// used instead of the native WinPcap methods.  The majority of these
	/// helper methods wrap up the status code error handling and throw an exception
	/// instead of just returning a status code and an error message string.
	/// </remarks>
	//[ SuppressUnmanagedCodeSecurity ]
	internal sealed class NativeMethods
	{
		/// <summary>
		/// Private constructor since this class is a utility class providing
		/// access to the WinPcap methods via PInvoke.
		/// </summary>
		NativeMethods( )
		{
		}
		
		/// <summary>
		/// Maximum size of the buffer for any error messages.
		/// </summary>
		public const int ErrorBufferSize = 256;
		
		/// <summary>
		/// Size of the buffer typically used within WinPcap (e.g. for host 
		/// names).
		/// </summary>
		public const int BufferSize = 1024;
		
		/// <summary>
		/// Specifies the default portion of the packet to capture.
		/// </summary>
		/// <remarks>
		/// No default is specified by the WinPcap library itself.  The
		/// value specified here should be big enough to capture the 
		/// largest packet that can be created under Windows.
		/// </remarks>
		public const int DefaultSnapLength = 65536;
		
		/// <summary>
		/// The default packet read timeout in milliseconds.
		/// </summary>
		public const int DefaultReadTimeout = 500;
	
		/// <summary>
		/// Socket address family.
		/// </summary>
		internal enum AddressFamily : short
		{
			/// <summary>
			/// No address family specified.
			/// </summary>
			None = 0,
			
			/// <summary>
			/// IPv4 address family.
			/// </summary>
			AF_INET = 2
		}
		
		/// <summary>
		/// Socket address structure.
		/// </summary>
		[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi ) ]
		internal struct sockaddr
		{
			/// <summary>
			/// The address family.
			/// </summary>
			[ MarshalAs( UnmanagedType.U2 ) ]
			public AddressFamily sa_family;              
			
			/// <summary>
			/// Up to 14 bytes of direct address.
			/// </summary>
			[ MarshalAs( UnmanagedType.ByValTStr , SizeConst=14 ) ]
			string sa_data;            
		}
		
		/// <summary>
		/// Socket address structure for IPv4.
		/// </summary>
		[ StructLayout( LayoutKind.Sequential, CharSet=CharSet.Ansi ) ]
		internal struct sockaddr_in
		{
			/// <summary>
			/// The address family.
			/// </summary>
			public AddressFamily sin_family;
			
			/// <summary>
			/// The IP port.</summary>
			[ MarshalAs( UnmanagedType.U2 ) ]
			public short sin_port;
			
			/// <summary>
			/// The first byte of the IP address
			/// </summary>
			public byte addr0;
			
			/// <summary>
			/// The second byte of the IP address
			/// </summary>
			public byte addr1;
			
			/// <summary>
			/// The third byte of the IP address
			/// </summary>
			public byte addr2;
			
			/// <summary>
			/// The fourth byte of the IP address
			/// </summary>
			public byte addr3;
			
			/// <summary>
			/// Up to 14 bytes of struct padding.
			/// </summary>
			[ MarshalAs( UnmanagedType.ByValTStr , SizeConst=8 ) ]         
			string sin_zero;
			
			/// <summary>
			/// Converts this socket address to an IPEndPoint
			/// </summary>
			public IPEndPoint ToIPEndPoint( )
			{
				byte[ ] Bytes = new byte[ 4 ] { addr0, addr1, addr2, addr3 };
				
				// Mask with 0xFFFFFFFF so we correctly convert the address of 
				// 255.255.255.255 since this converts to -1.
				long Address = BitConverter.ToInt32( Bytes, 0 ) & 0xFFFFFFFF;
				
				IPEndPoint EndPoint = new IPEndPoint( Address, sin_port );
				return EndPoint;
			}
		}
		
		/// <summary>
		/// The timeval structure is used to specify time values. It is associated 
		/// with the Berkeley Software Distribution (BSD) file Time.h.
		/// </summary>
		[ StructLayout( LayoutKind.Sequential ) ]
		internal struct timeval
		{
			/// <summary>
			/// Time value, in seconds. 
			/// </summary>
			int tv_sec;
			
			/// <summary>
			/// Time value, in microseconds. 
			/// </summary>
			int tv_usec;
		}
		
		/// <summary>
		/// Remote authentication 
		/// </summary>
		[ StructLayout( LayoutKind.Sequential ) ]
		internal struct pcap_rmtauth
		{
			/// <summary>
			/// Type of the authentication required.
			///
			/// In order to provide maximum flexibility, we can support different types
			/// of authentication based on the value of this 'type' variable. The currently 
			///	supported authentication mathods are:
			///	- RPCAP_RMTAUTH_NULL: if the user does not provide an authentication method
			///	(this could enough if, for example, the RPCAP daemon allows connections 
			///	from trusted hosts only)
			///	- RPCAP_RMTAUTH_PWD: if the user is willing to provide a valid 
			///	username/password to authenticate itself on the remote machine. Username/
			///	password must be valid on the remote machine.
			/// </summary>
			public int type;
			
			/// <summary>
			/// Zero-terminated string containing the username that has to be 
			/// used on the remote machine for authentication.
			/// 
			/// This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
			/// and it can be NULL.
			/// </summary>
			public IntPtr username;
		
			/// <summary>
			/// Zero-terminated string containing the password that has to be 
			/// used on the remote machine for authentication.
			/// 
			/// This field is meaningless in case of the RPCAP_RMTAUTH_NULL authentication
			/// and it can be NULL.
			/// </summary>
			public IntPtr password;
		}
		
		/// <summary>
		/// Network interface information returned from the WinPcap library.
		/// </summary>
		[ StructLayout( LayoutKind.Sequential ) ]
		internal struct pcap_if
		{
			/// <summary>
			/// If not <see cref="IntPtr.Zero"/>, a pointer to the next element in the 
			/// list; <see cref="IntPtr.Zero"/> for the last element of the list
			/// </summary>
			public IntPtr next;
			
			/// <summary>
			/// A pointer to the name for the device to pass to open_live
			/// </summary>
			public IntPtr name;

			/// <summary>
			/// If not <see cref="IntPtr.Zero"/>, a pointer to a string giving a 
			/// human-readable description of the device.
			/// </summary>
			public IntPtr description;
			
			/// <summary>
			/// A pointer to the first element of a list of addresses for the 
			/// interface.
			/// </summary>
			public IntPtr addresses;
			
			/// <summary>
			/// Interface flags. Currently the only possible flag is Loopback, 
			/// that is set if the interface is a loopback interface
			/// </summary>
			[ MarshalAs( UnmanagedType.U4 ) ]
			public NetworkInterfaceFlags flags;
			
			/// <summary>
			/// Converts a <see cref="pcap_if"/> struct into a
			/// <see cref="NetworkInterface"/> object.
			/// </summary>
			/// <returns>
			/// A new <see cref="NetworkInterface"/> object based on the values 
			/// contained in this <see cref="pcap_if"/> struct.
			/// </returns>
			public NetworkInterface ToNetworkInterface( )
			{
				NetworkInterface NetworkInterface = new NetworkInterface( );
				
				if( name != IntPtr.Zero )
				{
					NetworkInterface.Name = Marshal.PtrToStringAnsi( name );
				}
				
				if( description != IntPtr.Zero )
				{
					NetworkInterface.Description = Marshal.PtrToStringAnsi( description );
				}
						
				if( ( flags & NetworkInterfaceFlags.Loopback ) == NetworkInterfaceFlags.Loopback )
				{
					NetworkInterface.IsLoopback = true;
				}
				
				// Convert the network interface address structs.
								
				IntPtr AddressPtr = addresses;
				
				while( AddressPtr != IntPtr.Zero )
				{
					pcap_addr AddressInfo  = ( pcap_addr )Marshal.PtrToStructure( AddressPtr, typeof( pcap_addr ) );
					NetworkInterfaceAddress Address = AddressInfo.ToNetworkInterfaceAddress( );	
					NetworkInterface.Addresses.Add( Address );
					
					AddressPtr = AddressInfo.next;
				}
					
				return NetworkInterface;
			}
		}
		
		/// <summary>
		/// Network interface address information returned from the 
		/// WinPcap library.
		/// </summary>
		[ StructLayout( LayoutKind.Sequential ) ]
		internal struct pcap_addr
		{
			/// <summary>
			/// If not <see cref="IntPtr.Zero"/>, a pointer to the next element in the 
			/// list; <see cref="IntPtr.Zero"/> for the last element of the list
			/// </summary>
			public IntPtr next;	

			/// <summary>
			/// A pointer to a struct sockaddr containing an address.
			/// </summary>
			public IntPtr address;
 	
			/// <summary>
			/// If not <see cref="IntPtr.Zero"/>, a pointer to a struct sockaddr that 
			/// contains the netmask corresponding to the address pointed to by 
			/// <see cref="pcap_addr.address"/>.
			/// </summary>
			public IntPtr netmask;
			
			/// <summary>
			/// If not <see cref="IntPtr.Zero"/>, a pointer to a struct sockaddr that 
			/// contains the broadcast address corresponding to the address pointed 
			/// to by <see cref="pcap_addr.address"/>; may be <see cref="IntPtr.Zero"/> 
			/// if the interface doesn't support broadcasts.
			/// </summary>
			public IntPtr broadcastaddr;

			/// <summary>
			/// If not <see cref="IntPtr.Zero"/>, a pointer to a struct sockaddr that 
			/// contains the destination address corresponding to the address pointed 
			/// to by <see cref="pcap_addr.address"/>; may be null if the interface 
			/// isn't a point-to-point interface.
			/// </summary>
			public IntPtr dstaddr; 
			
			/// <summary>
			/// Converts a <see cref="pcap_addr"/> struct into a
			/// <see cref="NetworkInterfaceAddress"/> object.
			/// </summary>
			/// <returns>
			/// A new <see cref="NetworkInterfaceAddress"/> object based on the values 
			/// contained in this <see cref="pcap_addr"/> struct.
			/// </returns>
			public NetworkInterfaceAddress ToNetworkInterfaceAddress( )
			{
				NetworkInterfaceAddress NetworkInterfaceAddress = new NetworkInterfaceAddress( );

				if( address != IntPtr.Zero )
				{
					sockaddr SocketAddress = ( sockaddr )Marshal.PtrToStructure( address, typeof( sockaddr ) );
					
					if( SocketAddress.sa_family == AddressFamily.AF_INET )
					{
						// Extract IP address information.
						sockaddr_in InternetAddress = ( sockaddr_in )Marshal.PtrToStructure( address, typeof( sockaddr_in ) );
						NetworkInterfaceAddress.Address = InternetAddress.ToIPEndPoint( );
							
						// Extract netmask information.
						if( netmask != IntPtr.Zero )
						{
							sockaddr_in NetMaskAddress = ( sockaddr_in )Marshal.PtrToStructure( netmask, typeof( sockaddr_in ) );
							NetworkInterfaceAddress.NetMask = NetMaskAddress.ToIPEndPoint( );
						}
						
						// Extract broadcast address information.
						if( broadcastaddr != IntPtr.Zero )
						{
							sockaddr_in BroadcastAddress = ( sockaddr_in )Marshal.PtrToStructure( broadcastaddr, typeof( sockaddr_in ) );
							NetworkInterfaceAddress.BroadcastAddress = BroadcastAddress.ToIPEndPoint( );
						}
					}
				}
				
				return NetworkInterfaceAddress;
			}
		}
		
		/// <summary>
		/// A network interface flag.
		/// </summary>
		/// <remarks>
		/// Currently the only possible flag is Loopback, that is set if the interface 
		/// is a loopback interface.
		/// </remarks>
		[ Flags ]
		internal enum NetworkInterfaceFlags
		{
			/// <summary>
			/// No network interface specified.
			/// </summary>
			None = 0,
			
			/// <summary>
			/// The network interface is the loopback interface.
			/// </summary>
			Loopback = 0x01
		}
		
		/// <summary>
		/// Source type used when calling <see cref="pcap_createsrcstr"/>.
		/// </summary>
		internal enum SourceTypes
		{
			/// <summary>
			/// Local file.
			/// </summary>
			File = 2,
			
			/// <summary>
			/// Local interface.
			/// </summary>
			LocalInterface = 3,
			
			/// <summary>
			/// Remote interface.
			/// </summary>
			RemoteInterface = 4
		}
		
		/// <summary>
		/// Flag used when calling <see cref="pcap_open"/> method.
		/// </summary>
		[ Flags ]
		internal enum OpenFlags
		{
			/// <summary>
			/// No flags specified.
			/// </summary>
			None = 0,
			
			/// <summary>
			/// Selects promiscuous mode
			/// </summary>
			Promiscuous = 0x01,
			
			/// <summary>
			/// Selects who has to open the data connection(remote capture)
			/// </summary>
			ServerOpenDataPath = 0x02,
			
			/// <summary>
			/// Selects if the data connection has to be on top of UDP
			/// </summary>
			UdpDataPath = 0x04
		}
	
		/// <summary>
		/// A BPF pseudo-assembly program.
		/// </summary>
		[ StructLayout( LayoutKind.Sequential ) ]
		internal struct bpf_program
		{
			/// <summary>
			/// Indicates the number of instructions of the program, i.e. the number 
			/// of struct bpf_insn that will follow.</summary>
			[ MarshalAs( UnmanagedType.U4 ) ]
			int bf_len;
			
			/// <summary>
			/// A pointer to the first instruction of the program.
			/// </summary>
			IntPtr bf_insns;
		}
		
		/// <summary>
		/// Header of a packet in the dump file.
		/// </summary>
		[ StructLayout( LayoutKind.Sequential ) ]
		internal struct pcap_pkthdr
		{
			/// <summary>
			/// A <see cref="timeval"/> struct.
			/// </summary>
			public timeval timeval;
			
			/// <summary>
			/// Length of portion present.
			/// </summary>
			public int caplen; 
			
			/// <summary>
			/// Length of this packet (off wire) 
			/// </summary> 
			public uint len;  
		}
		
		/// <summary>
		/// Creates a list of network devices that can be opened with Open.
		/// </summary>
		/// <remarks>
		/// This method only works with WinPcap 3.0. The parameters
		/// have been changed in WinPcap 3.1, which is no longer backward
		/// compatible.
		/// </remarks>
		/// <param name="host">
		/// The address of the remote host on which we want to see the interface 
		/// list. It can be <see langword="null"/>: in this case the function queries 
		/// the local host  for the locally installed interfaces. The address can be 
		/// both numeric (e.g. '10.11.12.13', '1:2:3::4') and literal 
		/// (e.g. 'foo.bar.com').
		/// </param>
		/// <param name="port">
		/// A string (e.g. "2003") that keeps the network port on which we want to 
		/// connect to. It can be <see langword="null"/>: in this case the function 
		/// uses the standard port, defined in RPCAP_DEFAULT_NETPORT.
		/// </param>
		/// <param name="socketControlConnection">
		/// Socket to be used for the control connection. This parameter is meaningful 
		/// only if the control connection is already open when the pcap_findalldevs() 
		/// is called. This can be the case in which the 'ative' mode is used, in which 
		/// the capturing machine opens a control connection toward the client in order 
		/// to bypass in-middle firewalls. In that case, the control connection is 
		/// already open, and we have to use this one instead of opening a new one.
		/// </param>
		/// <param name="authentication">
		/// A pointer to a <see cref="pcap_rmtauth"/> structure. This pointer 
		/// keeps the information required to authenticate the RPCAP connection to the 
		/// remote host. This parameter is not meaningful in case of a query to the 
		/// local host: in that case it can be <see langword="null"/>.
		/// </param>
		/// <param name="devices">
		/// A pointer to a <see cref="pcap_if"/> struct, which will be 
		/// properly allocated inside this function. When the function returns, it is 
		/// set to point to the first element of the interface list; each element of 
		/// the list is of type 'struct <see cref="pcap_if"/>'.
		/// </param>
		/// <param name="error">
		/// The string builder (of size <see cref="ErrorBufferSize"/>) that will 
		/// contain the error message (in case there is one).
		/// </param>
		/// <returns>
		/// 0 if the call succeeded; otherwise -1.
		/// </returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_findalldevs_ex" ) ]
		public static extern int pcap_findalldevs_ex( [ MarshalAs( UnmanagedType.LPStr ) ] string host, 
		    [ MarshalAs( UnmanagedType.LPStr ) ] string port,
		    IntPtr socketControlConnection, 
		    IntPtr authentication,
		    [ Out ] out IntPtr devices,
		    StringBuilder error );
		
		/// <summary>
		/// Creates a list of network devices that can be opened with Open.
		/// </summary>
		/// <remarks>
		/// This method is not provided by the WinPcap library but is a 
		/// wrapper method which converts an error message into an
		/// exception.</remarks>
		/// <param name="host">
		/// The address of the remote host on which we want to see the interface 
		/// list. It can be <see langword="null"/>: in this case the function queries 
		/// the local host  for the locally installed interfaces. The address can be 
		/// both numeric (e.g. '10.11.12.13', '1:2:3::4') and literal 
		/// (e.g. 'foo.bar.com').
		/// </param>
		/// <param name="port">
		/// A string (e.g. "2003") that keeps the network port on which we want to 
		/// connect to. It can be <see langword="null"/>: in this case the function 
		/// uses the standard port, defined in RPCAP_DEFAULT_NETPORT.
		/// </param>
		/// <param name="socketControlConnection">
		/// Socket to be used for the control connection. This parameter is meaningful 
		/// only if the control connection is already open when the pcap_findalldevs() 
		/// is called. This can be the case in which the 'ative' mode is used, in which 
		/// the capturing machine opens a control connection toward the client in order 
		/// to bypass in-middle firewalls. In that case, the control connection is 
		/// already open, and we have to use this one instead of opening a new one.
		/// </param>
		/// <param name="authentication">
		/// A pointer to a <see cref="pcap_rmtauth"/> structure. This pointer 
		/// keeps the information required to authenticate the RPCAP connection to the 
		/// remote host. This parameter is not meaningful in case of a query to the 
		/// local host: in that case it can be <see langword="null"/>.
		/// </param>
		/// <returns>
		/// A pointer to a <see cref="pcap_if"/> struct, which will be 
		/// properly allocated inside this function. When the function returns, it is 
		/// set to point to the first element of the interface list; each element of 
		/// the list is of type 'struct <see cref="pcap_if"/>'.  If
		/// no interfaces were found this method will return <see langword="null"/>.
		/// </returns>
		/// <exception cref="WinPcapException">
		/// A <see cref="WinPcapException"/> is thrown if an error occurs whilst
		/// trying to read the available network interfaces.  Possible reasons 
		/// include:   
		/// <list type="bullet">
		/// 	<item>
		/// 		<description>libpcap/WinPcap was not installed on the 
		///        local/remote host</description>
		/// 	</item>
		/// 	<item>
		/// 		<description>the user does not have enough privileges to list 
		///      the devices</description>
		/// 	</item>
		/// 	<item>
		/// 		<description>a network problem</description>
		/// 	</item>
		/// 	<item>
		/// 		<description>the RPCAP version negotiation failed</description>
		/// 	</item>
		/// 	<item>
		/// 		<description>other errors (not enough memory and 
		///         others).</description>
		/// 	</item>
		/// </list>
		/// </exception>
		public static IntPtr pcap_findalldevs_ex( string host,
		    string port,
		    IntPtr socketControlConnection,
		    IntPtr authentication )
		{
			IntPtr NetworkInterfaces = IntPtr.Zero;
			
			StringBuilder ErrorText = CreateErrorBuffer( );
	
			int Status = pcap_findalldevs_ex( host,
				port,
				socketControlConnection,
				authentication,
				out NetworkInterfaces, 
				ErrorText );
			
			if( Status == -1 )
			{
				// An error occurred.
				throw new WinPcapException( ErrorText.ToString( ) );
			}
	
			return NetworkInterfaces;
		}
		
		/// <summary>
		/// Creates a list of network devices that can be opened with Open.
		/// </summary>
		/// <remarks>
		/// This method is not provided by the WinPcap library but is a 
		/// wrapper method which converts an error message into an
		/// exception.</remarks>
		/// <returns>
		/// A pointer to a <see cref="pcap_if"/> struct, which will be 
		/// properly allocated inside this function. When the function returns, it is 
		/// set to point to the first element of the interface list; each element of 
		/// the list is of type 'struct <see cref="pcap_if"/>'.  If
		/// no interfaces were found this method will return <see langword="null"/>.
		/// </returns>
		public static IntPtr pcap_findalldevs_ex( )
		{
			return pcap_findalldevs_ex( null, null, IntPtr.Zero, IntPtr.Zero );
		}
		
		/// <summary>
		/// Creates a list of network devices that can be opened with Open.
		/// </summary>
		/// <param name="devices">
		/// A pointer to a <see cref="pcap_if"/> struct, which will be 
		/// properly allocated inside this function. When the function returns, it is 
		/// set to point to the first element of the interface list; each element of 
		/// the list is of type 'struct <see cref="pcap_if"/>'.
		/// </param>
		/// <param name="error">
		/// The string builder (of size <see cref="ErrorBufferSize"/>) that will 
		/// contain the error message (in case there is one).
		/// </param>
		/// <returns>
		/// 0 if the call succeeded; otherwise -1.
		/// </returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_findalldevs" ) ]
		public static extern int pcap_findalldevs( [ Out ] out IntPtr devices,
		    StringBuilder error );
		
		/// <summary>
		/// Creates a list of network devices that can be opened with Open.
		/// </summary>
		/// <remarks>
		/// This method is not provided by the WinPcap library but is a 
		/// wrapper method which converts an error message into an
		/// exception.</remarks>
		/// <returns>
		/// A pointer to a <see cref="pcap_if"/> struct, which will be 
		/// properly allocated inside this function. When the function returns, it is 
		/// set to point to the first element of the interface list; each element of 
		/// the list is of type 'struct <see cref="pcap_if"/>'.  If
		/// no interfaces were found this method will return <see langword="null"/>.
		/// </returns>
		public static IntPtr pcap_findalldevs( )
		{
			IntPtr NetworkInterfaces = IntPtr.Zero;
			
			StringBuilder ErrorText = CreateErrorBuffer( );
	
			int Status = pcap_findalldevs( out NetworkInterfaces, 
				ErrorText );
			
			if( Status == -1 )
			{
				// An error occurred.
				throw new WinPcapException( ErrorText.ToString( ) );
			}
	
			return NetworkInterfaces;
		}
		
		/// <summary>
		/// Frees an interface list returned by <see cref="pcap_findalldevs_ex"/>.
		/// </summary>
		/// <param name="devices">
		/// The pointer to the interface list to be freed.  This should be a 
		/// pointer to a <see cref="pcap_if"/> struct as returned by
		/// the <see cref="pcap_findalldevs_ex"/> method.
		/// </param>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_freealldevs" ) ]
		public static extern void pcap_freealldevs( IntPtr devices );
		
		/// <summary>
		/// Accepts a set of strings (host name, port, ...), and it returns the 
		/// complete source string according to the new format 
		/// (e.g. 'rpcap://1.2.3.4/eth0').
		/// </summary>
		/// <param name="source">
		/// A user-allocated buffer that will contain the complete source string 
		/// when the function returns. This function assumes that the allocated buffer 
		/// is at least <see cref="BufferSize"/> bytes.
		/// </param>
		/// <param name="type">
		/// The type of the source we want to create.
		/// </param>
		/// <param name="host">
		/// The host (e.g. "foo.bar.com") we want to connect to. It can be 
		/// <see langword="null"/> in case we want to open an interface on a local 
		/// host.
		/// </param>
		/// <param name="port">
		/// The network port (e.g. "2002") we want to use for the RPCAP protocol. 
		/// It can be <see langword="null"/> in case we want to open an interface on a 
		/// local host.
		/// </param>
		/// <param name="name">
		/// A user-allocated buffer that keeps the interface name we want to use 
		/// (e.g. "eth0")
		/// </param>
		/// <param name="error">
		/// The string builder (of size <see cref="ErrorBufferSize"/>) that will 
		/// contain the error message (in case there is one).
		/// </param>
		/// <returns>
		/// 0 if the call succeeded; otherwise -1.
		/// </returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_createsrcstr" ) ]
		public static extern int pcap_createsrcstr( StringBuilder source,
			SourceTypes type,
			[ MarshalAs( UnmanagedType.LPStr ) ] string host,
			[ MarshalAs( UnmanagedType.LPStr ) ] string port,
			[ MarshalAs( UnmanagedType.LPStr ) ] string name,
			StringBuilder error );
		
		/// <summary>
		/// Accepts a set of strings (host name, port, ...), and it returns the 
		/// complete source string according to the new format 
		/// (e.g. 'rpcap://1.2.3.4/eth0').
		/// </summary>
		/// <param name="type">
		/// The type of the source we want to create.
		/// </param>
		/// <param name="host">
		/// The host (e.g. "foo.bar.com") we want to connect to. It can be 
		/// <see langword="null"/> in case we want to open an interface on a local 
		/// host.
		/// </param>
		/// <param name="port">
		/// The network port (e.g. "2002") we want to use for the RPCAP protocol. 
		/// It can be <see langword="null"/> in case we want to open an interface on a 
		/// local host.
		/// </param>
		/// <param name="name">
		/// A user-allocated buffer that keeps the interface name we want to use 
		/// (e.g. "eth0")
		/// </param>
		/// <returns>
		/// The complete source string.
		/// </returns>
		/// <exception cref="WinPcapException">
		/// A <see cref="WinPcapException"/> is thrown if an error occurs whilst
		/// trying to generate the source string. 
		/// </exception>
		public static string pcap_createsrcstr( SourceTypes type,
			string host,
			string port,
			string name )
		{
			StringBuilder Source = new StringBuilder( BufferSize );
			StringBuilder ErrorText = CreateErrorBuffer( );
			
			int Status = pcap_createsrcstr( Source, type, host, port, name, ErrorText );
			if( Status == -1 )
			{
				throw new WinPcapException( ErrorText.ToString( ) );
			}
			
			return Source.ToString( );
		}
		
		/// <summary>
		/// Accepts a set of strings (host name, port, ...), and it returns the 
		/// complete source string according to the new format 
		/// (e.g. 'rpcap://1.2.3.4/eth0').
		/// </summary>
		/// <param name="type">
		/// The type of the source we want to create.
		/// </param>
		/// <param name="name">
		/// An user-allocated buffer that keeps the interface name we want to use 
		/// (e.g. "eth0")
		/// </param>
		/// <exception cref="WinPcapException">
		/// A <see cref="WinPcapException"/> is thrown if an error occurs whilst
		/// trying to generate the source string. 
		/// </exception>
		/// <returns>
		/// The complete source string.
		/// </returns>
		public static string pcap_createsrcstr( SourceTypes type, string name )
		{
			return pcap_createsrcstr( type, null, null, name );
		}
		
		/// <summary>
		/// Opens a generic source in order to capture / send (WinPcap only) 
		/// traffic.
		/// </summary>
		/// <param name="source">
		/// the source name to open. The source name has to include the format prefix 
		/// according to the syntax proposed by WinPcap. It cannot be 
		/// <see langword="null"/>.
		/// </param>
		/// <param name="snaplen">
		/// Length of the packet that has to be retained. For each packet received 
		/// by the filter, only the first 'snaplen' bytes are stored in the buffer 
		/// and passed to the user application. For instance, snaplen equal to 100 
		/// means that only the first 100 bytes of each packet are stored. 
		/// </param>
		/// <param name="flags">
		/// Holds several flags that can be needed for capturing packets.
		/// </param>
		/// <param name="readTimeout">
		/// The read timeout in milliseconds. The read timeout is used to arrange 
		/// that the read not necessarily return immediately when a packet is seen, 
		/// but that it waits for some amount of time to allow more packets to arrive 
		/// and to read multiple packets from the OS kernel in one operation. Not all 
		/// platforms support a read timeout; on platforms that don't, the read timeout
		/// is ignored.
		/// </param>
		/// <param name="authentication">
		/// A pointer to a <see cref="pcap_rmtauth"/> struct that keeps the 
		/// information required to authenticate the user on a remote machine. In case 
		/// this is not a remote capture, this pointer can be set to 
		/// <see langword="null"/>.
		/// </param>
		/// <param name="error">
		/// The string builder (of size <see cref="ErrorBufferSize"/>) that will 
		/// contain the error message (in case there is one).
		/// </param>
		/// <returns>
		/// An opaque handle to the network interface.
		/// </returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_open" ) ]
		public static extern IntPtr pcap_open( [ MarshalAs( UnmanagedType.LPStr ) ] string source,
		    int snaplen,
		    OpenFlags flags,
		    int readTimeout,
		    IntPtr authentication,
		    StringBuilder error );
		
		/// <summary>
		/// Opens a generic source in order to capture / send (WinPcap only) 
		/// traffic.
		/// </summary>
		/// <returns>
		/// An opaque handle to the network interface.
		/// </returns>
		public static IntPtr pcap_open( string source )
		{
			StringBuilder ErrorText = CreateErrorBuffer( );
			
			IntPtr NetworkInterfacePtr = pcap_open( source, DefaultSnapLength, OpenFlags.None, DefaultReadTimeout, IntPtr.Zero, ErrorText );
			
			if( NetworkInterfacePtr == IntPtr.Zero )
			{
				throw new WinPcapException( ErrorText.ToString( ) );
			}
			
			return NetworkInterfacePtr;
		}
		
		/// <summary>
		/// Closes the files associated with the network interface and deallocates 
		/// resources.
		/// </summary>
		/// <param name="networkInterface">
		/// A pointer to the network interface returned by the <see cref="pcap_open"/>
		/// method.99
		/// </param>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_close" ) ]
		public static extern void pcap_close( IntPtr networkInterface );
		
		/// <summary>
		/// Returns the link layer of an adapter.
		/// </summary>
		/// <param name="networkInterface">The network interface pointer.</param>
		/// <returns>The <see cref="DataLinkLayerType"/>.</returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_datalink" ) ]
		public static extern DataLinkLayerType pcap_datalink( IntPtr networkInterface );
		
		/// <summary>
		/// Compiles a packet filter. Converts an high level filtering expression 
		/// in a program that can be interpreted by the kernel-level filtering engine.
		/// </summary>
		/// <param name="networkInterface">The network interface
		/// that the packet filter will apply to.</param>
		/// <param name="fp">A bpf_program struct.</param>
		/// <param name="filterString">The packet filter string.</param>
		/// <param name="optimize">Optimize controls whether optimization on the
		/// resulting code is performed</param>
		/// <param name="netmask">The netmask specifies the netmask of the local 
		/// net.</param>
		/// <returns>0 if the call succeeded; -1 otherwise.  The error information
		/// can be retrieved from <see cref="pcap_geterr"/>.</returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_compile" ) ]
		public static extern int pcap_compile( IntPtr networkInterface,
		    ref bpf_program fp,
			[ MarshalAs( UnmanagedType.LPStr ) ] string filterString,
			int optimize,
			[ MarshalAs( UnmanagedType.U4 ) ] int netmask );
		
		
		/// <summary>
		/// Compiles a packet filter. Converts an high level filtering expression 
		/// in a program that can be interpreted by the kernel-level filtering engine.
		/// </summary>
		/// <remarks>This method is not provided by the WinPcap library, but is
		/// a wrapper method which turns the status code into an exception.</remarks>
		/// <param name="networkInterface">The network interface
		/// that the packet filter will apply to.</param>
		/// <param name="filterString">The packet filter string.</param>
		/// <param name="optimize">Optimize controls whether optimization on the
		/// resulting code is performed</param>
		/// <param name="netmask">The netmask specifies the netmask of the local 
		/// net.</param>
		/// <returns>The filled in <see cref="bpf_program"/> struct.</returns>
		/// <exception cref="WinPcapException">A <see cref="WinPcapException"/>
		/// is thrown if the compilation fails.</exception>
		public static bpf_program pcap_compile( IntPtr networkInterface, 
		    [ MarshalAs( UnmanagedType.LPStr ) ] string filterString,
			int optimize,
			[ MarshalAs( UnmanagedType.U4 ) ] int netmask )
		{
			bpf_program bp = new bpf_program( );
			
			int Status = pcap_compile( networkInterface, ref bp, filterString, optimize, netmask );
			if( Status == -1 )
			{
				string ErrorText = pcap_geterr( networkInterface, "Filter compilation error." );
				throw new WinPcapException( ErrorText );
			}
			
			return bp;
		}
		
		/// <summary>
		/// Returns the error text pertaining to the last pcap library error.
		/// </summary>
		/// <param name="networkInterface">The network interface where the
		/// error occurred.</param>
		/// <returns>A pointer to a string containing the error.</returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_geterr" ) ]
		public static extern IntPtr pcap_geterr( IntPtr networkInterface );
		
		/// <summary>
		/// Returns the error text pertaining to the last pcap library error.
		/// </summary>
		/// <param name="networkInterface">The network interface where the
		/// error occurred.</param>
		/// <param name="defaultError">The default error text that will be
		/// returned if no errors could be retrieved by <see cref="pcap_geterr"/>.</param>
		/// <returns>A string containing the error.  If no error could be
		/// retrieved it returns the error message provided by 
		/// <paramref name="error"/>.</returns>
		public static string pcap_geterr( IntPtr networkInterface, string defaultError )
		{
			string Error = defaultError;
			
			IntPtr ErrorPtr = pcap_geterr( networkInterface );
			if( ErrorPtr != IntPtr.Zero )
			{
				Error = Marshal.PtrToStringAnsi( ErrorPtr );
			}
			
			return Error;
		}
		
		/// <summary>
		/// Associates a filter to a capture. 
		/// </summary>
		/// <param name="networkInterface">The network interface.</param>
		/// <param name="fp">A <see cref="bpf_program"/> struct, usually the result of 
		/// a call to <see cref="pcap_compile"/>.</param>
		/// <returns>0 for success; otherwise -1.</returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_setfilter" ) ]
		public static extern int pcap_setfilter( IntPtr networkInterface, [ In, Out ] ref bpf_program fp );
		
		/// <summary>
		/// Associates a filter to a capture.
		/// </summary>
		/// <remarks>This method is not provided by the WinPcap library, but is
		/// a wrapper method which throws an exception instead of returning
		/// a status code.</remarks>
		/// <param name="networkInterface">The network interface.</param>
		/// <param name="fp">A <see cref="bpf_program"/> struct, usually the result of 
		/// a call to <see cref="pcap_compile"/>.</param>
		/// <exception cref="WinPcapException">A <see cref="WinPcapException"/>
		/// is thrown if the filter cannot be set.</exception>
		public static void SetPacketFilter( IntPtr networkInterface, ref bpf_program fp )
		{
			int Status = pcap_setfilter( networkInterface, ref fp );
			if( Status == -1 )
			{
				string ErrorText = pcap_geterr( networkInterface, "SetFilter failed." );
				throw new WinPcapException( ErrorText );
			}
		}
		
		/// <summary>
		/// Associates a filter to a capture.
		/// </summary>
		/// <remarks>This method is not provided by the WinPcap library, but is
		/// a wrapper method which compiles the string filter and throws an exception 
		/// instead of returning a status code if an error occurs.</remarks>
		/// <param name="networkInterface">The network interface.</param>
		/// <param name="filterString">The packet filter string.</param>
		/// <param name="optimize">Optimize controls whether optimization on the
		/// resulting code is performed</param>
		/// <param name="netmask">The netmask specifies the netmask of the local 
		/// net.</param>
		/// <exception cref="WinPcapException">A <see cref="WinPcapException"/>
		/// is thrown if the filter cannot be set.</exception>
		public static void SetPacketFilter( IntPtr networkInterface,
		    string filterString,
			int optimize,
			int netmask )
		{
			bpf_program fp = pcap_compile( networkInterface, filterString, optimize, netmask );
			SetPacketFilter( networkInterface, ref fp );
			pcap_freecode( ref fp );
		}
		
		/// <summary>
		/// Read a packet from an interface or from an offline capture.
		/// </summary>
		/// <remarks>Win32 specific.</remarks>
		/// <param name="networkInterface">The network interface to retrieve
		/// a packet from.</param>
		/// <param name="header">A pointer to a <see cref="pcap_pkthdr"/>
		/// struct.</param>
		/// <param name="data">The packet's data.</param>
		/// <returns>The return value can be:
		///	<list type="bullet">
		/// 	<item>
		/// 		<description>1 if the packet has been read without 
		/// 		problems</description>
		/// 	</item>
		/// 	<item>
		/// 		<description>0 if the timeout set with pcap_open_live() has 
		///         elapsed. In this case packetHeader and packetData do not point 
		///         to a valid packet.</description>
		/// 	</item>
		/// 	<item>
		/// 		<description>-1 if an error occurred</description>
		/// 	</item>
		/// 	<item>
		/// 		<description>-2 if EOF was reached reading from an offline 
		///         capture</description>
		/// 	</item>
		/// </list>
		/// </returns>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_next_ex" ) ]
		public static extern int pcap_next_ex( IntPtr networkInterface,
		    out IntPtr header,
		    out IntPtr data );
		
		/// <summary>
		/// Frees a filter.
		/// </summary>
		/// <param name="fp">A <see cref="bpf_program"/> struct that 
		/// was created via a call to <see cref="pcap_compile"/>.</param>
		[ DllImport( "wpcap.dll", EntryPoint="pcap_freecode" ) ]
		public static extern void pcap_freecode( ref bpf_program fp );
		
		/// <summary>
		/// Creates a <see cref="StringBuilder"/> that is big enough
		/// to hold any WinPcap error strings.
		/// </summary>
		static StringBuilder CreateErrorBuffer( )
		{
			// Use ErrorBufferSize + 1.  This is best practice according to the
			// various WinPcap headers.
			StringBuilder ErrorBuffer = new StringBuilder( ErrorBufferSize + 1 );
			return ErrorBuffer;
		}
	}
}
